/**
@author		Jong Min, Lee
@date		  01/15/2014
@breif		Viewer controller class

copyright(c) Tae Young Soft. All right reserved. 2014
*/
#pragma once

#include <vector>
#include <list>

#include "Taurus_Util/Macros.h"
#include "Taurus_Util/TUTypes.h"
#include "Taurus_Util/Delegate.h"
#include "Taurus_Viewer/MonitorGroupProperty.h"
#include "Taurus_Viewer/StudyViewLayoutProperty.h"

//forward declarations
class CMonitorWnd;
class CVisibleToolbar;
class CHiddenToolbar;
class CMonitor;
class CStudyWorkSpace;
class CStudyTab;

class CViewerController
{
private:

  /**
  @brief		default constructor
  */
  CViewerController();

  DISALLOW_COPY_AND_ASSIGN(CViewerController);

public:
  /**
  @brief		destructor
  */
  ~CViewerController();

  /**
  @brief		get the single instance of this class
  @return		pointer to the single instance of this class
  */
  static CViewerController* getInstance();

  /**
  @brief		configure
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD doConfigure();

  /**
  @brief		set monitor group
  @param		group null-terminated string represent monitor layout
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD setMonitorGroup(const TCHAR* group);

  /**
  @brief		set study work space layout of monitor 
  @param		monitorIndex the index number of monitor
  @param    swsLayout study work space layout
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD setSWSLayout(unsigned int monitorIndex, const C2DLayout& swsLayout);

  /**
  @brief		access to monitor group property
  @return		pointer to monitor group property
  */
  inline const CMonitorGroupProperty* getMonitorGroupProperty() const
  {
    return &m_theMonitorGroups;
  }

  /**
  @brief		get the study view layout property
  @return		pointer to study view layout property
  */
  inline const CStudyViewLayoutProperty* getStudyViewLayoutProperty() const
  {
    return &m_theStudyViewLayout;
  }

  /**
  @brief		show viewer on specified monitor
  @param		pMonitor pointer to monitor
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD ShowViewer(const CMonitor* pMonitor);

protected:
  /**
  @brief		handling onChangedCurSelMLayout event of visible toolbar
  */
  TDelegate<CViewerController, CVisibleToolbar> m_theTBMLayoutHandler;

  /**
  @brief		delegate for onChangedCurSelLayout event of visible toolbar
  */
  TDelegate<CViewerController, CVisibleToolbar> m_theTBSLayoutHandler;

  /**
  @brief		delegate for onClickedHide event of visible toolbar
  */
  TDelegate<CViewerController, CVisibleToolbar> m_theTBHideHandler;

  /**
  @brief		delegate for onSelectItem event of hidden toolbar
  */
  TDelegate<CViewerController, CHiddenToolbar> m_theHiddenTBSelectItemHandler;

private:
  /**
  @brief		configure monitor
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD doConfigureMonitors();

  /**
  @brief		initialize monitory group property
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD initMonitorGroupPropety();

  /**
  @brief		initialize study view layout property
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD initStudyViewLayoutProperty();

  /**
  @brief		configure toolbar
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD doConfigureToolbars();

  /**
  @brief		craate and configure study tab
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD doConfigureStudyTabs();

  /**
  @brief		init data members
  */
  void init();

  /**
  @brief		destroy all data memember
  */
  void destroy();

  /**
  @brief		arrange ui controls initially
  */
  void initialArrange();

  /**
  @brief		arrange ui controls on a given monitor window
  @param		monitorInex monitor index
  @return   ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD arrangeControls(const unsigned int monitorIndex);

  /**
  @brief		remove all visible toolbars
  */
  void removeAllVisibleToolbars();

  /**
  @brief		remove all hidden toolbars
  */
  void removeAllHiddenToolbars();

  /**
  @brief		remove all monitor windows
  */
  void removeAllMonitorWnds();

  /**
  @brief		remove all study tabs
  */
  void removeAllStudyTabs();

  /**
  @brief		create a new study work space
  @param		outSWS variable in which pointer to the new study work space is stored
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD createSWS(CStudyWorkSpace*& outSWS);

  /**
  @brief		create a new study work space and add it list
  @param		outSWS variable in whcih pointer to the new study work space is stored
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD createAndAddSWS(CStudyWorkSpace*& outSWS);

  /**
  @brief		create new study workspaces for a monitor group and add them to list
  @param		groupIndex the index number of monitor group
  @param    layout study workspace layout
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD createAndAddSWS(const unsigned int groupIndex, const C2DLayout& layout);

  /**
  @brief		calculate the number of study work spaces that need to be created
  @param		groupIndex the index number of monitor group
  @param    layout study work space layout of monitor group
  @return		the number of study work spaces that need to be created
  */
  unsigned int calcNumSWSNeeded(unsigned int groupIndex, const C2DLayout& layout);

  /**
  @brief		find study work space by unique id
  @param		uid unique id of study work space to be found
  @param    indexInList variable in which pointer to the index number of study work space in list is stored
  @return		pointer to study work space if found, NULL if not
  */
  CStudyWorkSpace* findSWS(const unsigned int uid, unsigned int* indexInList);

  /**
  @brief		find study wor space that has foucs
  @param		indexInList variable in which pointer to the index number of focused study work space in list is stored
  @return		pointer to focused work space if found, NULL if not
  */
  CStudyWorkSpace* findFocusedSWS(unsigned int* indexInList);

  /**
  @brief		set monitor groups by using monitor layout 
  @param		currentLayout current monitor layout
  @param    newLayout new monitor layout
  @param    changeSWSLayout flag indicating whether study work space layout is to be chagned
  @param    movefocusedSWSFront flag indicating whether focused study work space is to be moved to front of list
  @param    redraw flag indicating whether study work spaces are to be redrawn
  @return		ERROR_SUCCESS if success, an error code otherwise
  */
  DWORD setMonitorGroup(const CString& oldLayout,
                        const CString& newLayout,
                        BOOL changeSWSLayout,
                        BOOL moveFocuseSWSFront,
                        BOOL redraw);
  /**
  @brief		this function is called whenever the monitor group is changed
  */
  void onMonitorGroupChanged();

  /**
  @brief		this function is called whenever the study work space layout is changed
  */
  void onSWSLayoutChanged();

  /**
  @brief		attach monitors to study work spaces
  @param		redraw flag indicating whether study work spaces are to be redrawn or not
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD attachSWSsToMonitors(BOOL redraw);

  /**
  @brief		move focused study work psace and empty study work spaces to front of list
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD moveFocusedAndOccupiedSWSToFront();

  /**
  @brief		calculate work area of study work space in monitor window
  @param		monitorIndex the index number of monitor
  @return		work area
  */
  CRect calcSWSWorkArea(const unsigned int monitorIndex) const;

  /**
  @brief		make a study work space focused
  @param		uid unique id of study workspace
  @param    redraw flag indicating study work spaces to be redrawn
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  void setFocusedSWS(const unsigned int uid, BOOL redraw);

  /**
  @brief		hanlding monitor layout combo box 
  */
  void monitorLayout_Changed(const CVisibleToolbar* visibleTB, void* parameter);

  /**
  @brief		handling study view layout combo box
  */
  void studyViewLayout_Changed(const CVisibleToolbar* visibleTB, void* parameter);

  /**
  @brief		handling hide button event of visible toolbar
  */
  void hideButton_Clicked(const CVisibleToolbar* visibleTB, void* parameter);

  /**
  @brief		handling selecting item of hidden toolbar
  */
  void selectItem(const CHiddenToolbar* hiddenTB, void* parameter);

private:
  //pointer to the single instance of this class
  static CViewerController* m_pInstance;

  //monitor windows
  std::vector<CMonitorWnd*> m_arrMonitorWnds;

  //visible toolbar
  std::vector<CVisibleToolbar*> m_arrVisibleToolbars;

  //hidden toolbar
  std::vector<CHiddenToolbar*> m_theHiddenToolbars;

  //study tab
  std::vector<CStudyTab*> m_theStudyTabs;

  //monitor group property
  CMonitorGroupProperty m_theMonitorGroups;

  //study view layout property
  CStudyViewLayoutProperty m_theStudyViewLayout;

  //study workspace list
  std::list<CStudyWorkSpace*> m_theSWSs;

};
